package com.cinc.mdm.modules.bom.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cinc.mdm.modules.bom.entity.MdmBom;
import com.cinc.mdm.modules.bom.entity.MdmBomDetail;
import com.cinc.mdm.modules.bom.mapper.MdmBomDetailMapper;
import com.cinc.mdm.modules.bom.mapper.MdmBomMapper;
import com.cinc.mdm.modules.bom.service.IMdmBomService;
import com.cinc.mdm.modules.bom.vo.MdmBomMutilLevelPage;
import com.cinc.mdm.modules.bom.vo.MdmBomPage;
import com.cinc.mdm.modules.bom.vo.MdmBomTreePage;
import com.cinc.mdm.modules.material.entity.MdmMaterial;
import com.cinc.mdm.modules.material.mapper.MdmMaterialMapper;
import com.cinc.mdm.modules.material.service.IMdmMaterialService;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description: bom主记录
 * @Author: jeecg-boot
 * @Date:   2021-10-24
 * @Version: V1.0
 */
@Service
public class MdmBomServiceImpl extends ServiceImpl<MdmBomMapper, MdmBom> implements IMdmBomService {

	@Autowired
	private MdmBomMapper mdmBomMapper;
	@Autowired
	private MdmBomDetailMapper mdmBomDetailMapper;
	@Autowired
	private IMdmMaterialService mdmMaterialService;

	/**
	 * 批量添加一对多
	 *
	 */
	@Override
	@Transactional
	public void saveBatchMain(List<MdmBomPage> mdmBomList){
		if(oConvertUtils.listIsEmpty(mdmBomList)){
			return;
		}
		batchCheckMaterialInfo(mdmBomList);
		// BOM主表重复校验
		List<MdmBomPage> existsBomList = mdmBomMapper.selectByMaterialCodeAndFactory(mdmBomList);
		if (oConvertUtils.listIsNotEmpty(existsBomList)) {
			String materialCodeStr = String.join(",", existsBomList.stream().map(MdmBomPage::getMaterialCode).collect(Collectors.toList()));
			throw new RuntimeException("物料BOM已存在；物料编号：" + materialCodeStr);
		}
		// 保存
		for(MdmBomPage mdmBomPage : mdmBomList){
			MdmBom mdmBom = new MdmBom();
			BeanUtils.copyProperties(mdmBomPage, mdmBom);
			mdmBomMapper.insert(mdmBom);

			if(oConvertUtils.listIsNotEmpty(mdmBomPage.getMdmBomDetailList())) {
				for(MdmBomDetail entity : mdmBomPage.getMdmBomDetailList()) {
					//外键设置
					entity.setMainId(mdmBom.getId());
					entity.setSuperMaterialId(mdmBom.getMaterialId());
					mdmBomDetailMapper.insert(entity);
				}
			}
		}
	}

	@Override
	@Transactional
	public void saveMain(MdmBom mdmBom, List<MdmBomDetail> mdmBomDetailList) {
		if(StringUtils.isBlank(mdmBom.getMaterialId()) || StringUtils.isBlank(mdmBom.getFactory())){
			throw new RuntimeException("BOM物料编号/工厂不能为空!");
		}
		LambdaQueryWrapper<MdmBom> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MdmBom::getMaterialId, mdmBom.getMaterialId()).eq(MdmBom::getFactory, mdmBom.getFactory());
		Integer mainCount = mdmBomMapper.selectCount(queryWrapper);
		if(mainCount > 0){
			throw new RuntimeException("物料BOM已存在");
		}
		mdmBomMapper.insert(mdmBom);

		if(oConvertUtils.listIsNotEmpty(mdmBomDetailList)) {
			long detailCount = mdmBomDetailList.stream().map(MdmBomDetail::getMaterialCode).distinct().count();
			if(detailCount !=  mdmBomDetailList.size()){
				throw new RuntimeException("子BOM物料编号重复");
			}
			for(MdmBomDetail entity:mdmBomDetailList) {
				//外键设置
				entity.setMainId(mdmBom.getId());
				entity.setSuperMaterialId(mdmBom.getMaterialId());
				mdmBomDetailMapper.insert(entity);
			}
		}
	}

	/**
	 * bom物料信息校验
	 *
	 * @param bomPageList
	 */
	private void batchCheckMaterialInfo(List<MdmBomPage> bomPageList){
		if(oConvertUtils.listIsEmpty(bomPageList)){
			return;
		}
		Map<String,String> materialCodeAndId = new HashMap<>();
		long materialIdNullCount = bomPageList.stream().filter(bom -> StringUtils.isBlank(bom.getMaterialId())).count();
		if(materialIdNullCount > 0){
			List<String> materialCodeList = bomPageList.stream().map(MdmBomPage::getMaterialCode).collect(Collectors.toList());
			List<MdmMaterial> materialList = mdmMaterialService.list(new LambdaQueryWrapper<MdmMaterial>().in(MdmMaterial::getMaterialCode, materialCodeList));
			materialCodeAndId = materialList.stream().collect(Collectors.toMap(MdmMaterial::getMaterialCode, MdmMaterial::getId));
		}

		for(MdmBomPage bomPage : bomPageList){
			if((StringUtils.isBlank(bomPage.getMaterialId()) && StringUtils.isBlank(bomPage.getMaterialCode()))
				|| StringUtils.isBlank(bomPage.getFactory())){

				throw new RuntimeException("BOM物料编号/工厂不能为空!");
			}
			if(StringUtils.isBlank(bomPage.getMaterialId())){
				if(StringUtils.isBlank(materialCodeAndId.get(bomPage.getMaterialCode()))){
					throw new RuntimeException("未找到物料信息，物料编号：" + bomPage.getMaterialCode());
				}
				bomPage.setMaterialId(materialCodeAndId.get(bomPage.getMaterialCode()));
			}

			List<MdmBomDetail> bomDetailList = bomPage.getMdmBomDetailList();
			if(oConvertUtils.listIsEmpty(bomDetailList)){
				continue;
			}
			Map<String,String> dMaterialCodeAndId = new HashMap<>();
			if(materialIdNullCount > 0){
				List<String> dMaterialCodeList = bomDetailList.stream().map(MdmBomDetail::getMaterialCode).collect(Collectors.toList());
				List<MdmMaterial> dMaterialList = mdmMaterialService.list(new LambdaQueryWrapper<MdmMaterial>().in(MdmMaterial::getMaterialCode, dMaterialCodeList));
				dMaterialCodeAndId = dMaterialList.stream().collect(Collectors.toMap(MdmMaterial::getMaterialCode, MdmMaterial::getId));
			}
			List<String> materialCodeDistinctList = new ArrayList<>();
			for(MdmBomDetail bomDetail : bomDetailList){
				if(StringUtils.isBlank(bomDetail.getMaterialId()) && StringUtils.isBlank(bomDetail.getMaterialCode())){
					throw new RuntimeException("子BOM物料编号不能为空!");
				}
				if(StringUtils.isBlank(bomDetail.getMaterialId())){
					if(StringUtils.isBlank(dMaterialCodeAndId.get(bomDetail.getMaterialCode()))){
						throw new RuntimeException("未找到物料信息，物料编号：" + bomDetail.getMaterialCode());
					}
					bomDetail.setMaterialId(dMaterialCodeAndId.get(bomDetail.getMaterialCode()));
				}
				if(!materialCodeDistinctList.contains(bomDetail.getMaterialCode())){
					materialCodeDistinctList.add(bomDetail.getMaterialCode());
				}
			}
			if(bomDetailList.size() != materialCodeDistinctList.size()){
				throw new RuntimeException("子BOM物料编号重复，主物料编号：" + bomPage.getMaterialCode());
			}
		}
	}

	@Override
	@Transactional
	public void updateMain(MdmBom mdmBom,List<MdmBomDetail> mdmBomDetailList, List<String> mdmBomDetailDeleteIdList,
						   List<String> mdmBomDetailAddIdList) {
		// 主表处理
		LambdaQueryWrapper<MdmBom> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MdmBom::getMaterialId,mdmBom.getMaterialId()).eq(MdmBom::getFactory, mdmBom.getFactory());
		List<MdmBom> mdmBomList = mdmBomMapper.selectList(queryWrapper);
		if(oConvertUtils.listIsNotEmpty(mdmBomList) && (mdmBomList.size() > 1 || !mdmBomList.get(0).getId().equals(mdmBom.getId()))){
			throw new RuntimeException("BOM已存在!");
		}
		mdmBomMapper.updateById(mdmBom);

		// 子表数据处理
		if(oConvertUtils.listIsNotEmpty(mdmBomDetailList)){
			long detailCount = mdmBomDetailList.stream().map(MdmBomDetail::getMaterialCode).distinct().count();
			if(detailCount !=  mdmBomDetailList.size()){
				throw new RuntimeException("子BOM物料编号重复");
			}
			// 1.子表数据新增/修改
			for(MdmBomDetail entity : mdmBomDetailList) {
				//外键设置
				entity.setMainId(mdmBom.getId());
				entity.setSuperMaterialId(mdmBom.getMaterialId());
				if(oConvertUtils.listIsNotEmpty(mdmBomDetailAddIdList) && mdmBomDetailAddIdList.contains(entity.getId())){
					// 新增
					mdmBomDetailMapper.insert(entity);
				}else{
					// 修改
					int i = mdmBomDetailMapper.updateById(entity);
					if(i == 0){
						throw new RuntimeException("数据不存在；物料号：" + entity.getMaterialCode() + " 物料描述：" + entity.getMaterialDesc());
					}
				}
			}

			// 2.子表数据删除
			if(oConvertUtils.listIsNotEmpty(mdmBomDetailDeleteIdList)){
				mdmBomDetailDeleteIdList.forEach(deleteId -> mdmBomDetailMapper.deleteById(deleteId));
			}
		}
	}

	/**
	 * 批量添加/修改一对多,excel导入使用
	 *
	 */
	@Transactional
	@Override
	public void saveOrUpdBatchMain(List<MdmBomPage> mdmBomPageList){
		if(oConvertUtils.listIsEmpty(mdmBomPageList)){
			return;
		}
		batchCheckMaterialInfo(mdmBomPageList);
		List<MdmBomPage> mainAddList = new ArrayList<>();
		List<MdmBomPage> mainUpdList = new ArrayList<>();
		List<MdmBomPage> existsBomList = mdmBomMapper.selectByMaterialCodeAndFactory(mdmBomPageList);
		if(oConvertUtils.listIsNotEmpty(existsBomList)){
			Map<String, String> materialCodeFactoryAndBomId = existsBomList.stream().collect(Collectors.toMap(bomPage -> bomPage.getMaterialCode()+bomPage.getFactory(), MdmBomPage::getId));
			for(MdmBomPage bomPage : mdmBomPageList) {
				if(materialCodeFactoryAndBomId.containsKey(bomPage.getMaterialCode()+bomPage.getFactory())){
					bomPage.setId(materialCodeFactoryAndBomId.get(bomPage.getMaterialCode()+bomPage.getFactory()));
					mainUpdList.add(bomPage);
				}else{
					mainAddList.add(bomPage);
				}
			}
		}else{
			mainAddList = mdmBomPageList;
		}
		// 新增
		if(oConvertUtils.listIsNotEmpty(mainAddList)){
			for(MdmBomPage bomPage : mainAddList){
				MdmBom mdmBom = new MdmBom();
				BeanUtils.copyProperties(bomPage, mdmBom);
				mdmBomMapper.insert(mdmBom);
				if(oConvertUtils.listIsNotEmpty(bomPage.getMdmBomDetailList())) {
					for(MdmBomDetail entity : bomPage.getMdmBomDetailList()) {
						//外键设置
						entity.setMainId(mdmBom.getId());
						entity.setSuperMaterialId(mdmBom.getMaterialId());
						mdmBomDetailMapper.insert(entity);
					}
				}
			}
		}
		// 修改
		if(oConvertUtils.listIsNotEmpty(mainUpdList)){
			for(MdmBomPage mainUpd : mainUpdList){
				MdmBom mdmBom = new MdmBom();
				BeanUtils.copyProperties(mainUpd, mdmBom);
				mdmBomMapper.updateById(mdmBom);

				List<MdmBomDetail> mdmBomDetailList = mainUpd.getMdmBomDetailList();
				if(oConvertUtils.listIsNotEmpty(mdmBomDetailList)){
					Map<String, String> detailCodeAndId = new HashMap<>();
					List<String> detailMaterialCodeList = mdmBomDetailList.stream().map(MdmBomDetail::getMaterialCode).collect(Collectors.toList());
					List<MdmBomDetail> bomDetailUpdList = mdmBomDetailMapper.selectByMaterialCodeAndMainId(detailMaterialCodeList, mdmBom.getId());
					if(oConvertUtils.listIsNotEmpty(bomDetailUpdList)){
						detailCodeAndId = bomDetailUpdList.stream().collect(Collectors.toMap(MdmBomDetail::getMaterialCode, MdmBomDetail::getId));
					}
					for(MdmBomDetail bomDetail : mdmBomDetailList){
						bomDetail.setMainId(mdmBom.getId());
						bomDetail.setSuperMaterialId(mdmBom.getMaterialId());

						if(StringUtils.isNotBlank(detailCodeAndId.get(bomDetail.getMaterialCode()))){
							bomDetail.setId(detailCodeAndId.get(bomDetail.getMaterialCode()));
							mdmBomDetailMapper.updateById(bomDetail);
						}else{
							mdmBomDetailMapper.insert(bomDetail);
						}
					}
				}
			}
		}
	}

	@Override
	@Transactional
	public void delMain(String id) {
		mdmBomDetailMapper.deleteByMainId(id);
		mdmBomMapper.deleteById(id);
	}

	@Override
	@Transactional
	public void delBatchMain(Collection<? extends Serializable> idList) {
		for(Serializable id:idList) {
			mdmBomDetailMapper.deleteByMainId(id.toString());
			mdmBomMapper.deleteById(id);
		}
	}

	@Override
	public IPage<MdmBomPage> pageList(Page<MdmBomPage> page, MdmBomPage mdmBomPage) {

		return mdmBomMapper.selectPageList(page, mdmBomPage);
	}

	@Override
	public List<MdmBomPage> listBom(MdmBomPage mdmBomPage) {
		return mdmBomMapper.selectBomList(mdmBomPage);
	}

	@Override
	public List<MdmBomTreePage> queryTreeList(String materialDesc, String materialTypeCode, String levelType) {
		// 查询顶级bom列表
		List<MdmBomTreePage> mdmBomTreeList = mdmBomMapper.selectTreeTopList(materialDesc, materialTypeCode);
		// 构造树形
		if(oConvertUtils.listIsNotEmpty(mdmBomTreeList)) {
			for(MdmBomTreePage bom : mdmBomTreeList){
				bom.setSumQty(BigDecimal.ONE);
				setMdmBomTree(bom, levelType);
			}
		}

		return mdmBomTreeList;
	}

	@Override
	public MdmBomTreePage queryTree(String materialId, BigDecimal reqQty) {
		// 查询顶级bom列表
		MdmBomTreePage mdmBomTop = mdmBomMapper.selectTreeTop(materialId);
		if(mdmBomTop == null){
			return null;
		}
		// 构造树形
		reqQty = reqQty == null ? BigDecimal.ONE : reqQty;
		mdmBomTop.setSumQty(reqQty);
		setMdmBomTree(mdmBomTop, "02");

		return mdmBomTop;
	}

	private void setMdmBomTree(MdmBomTreePage bomTreePage, String levelType){
		bomTreePage.setKeyAndTitle();
		List<MdmBomTreePage> childList = mdmBomDetailMapper.selectTreeListNextLevel(bomTreePage.getMaterialId(), bomTreePage.getFactory());
		if(oConvertUtils.listIsNotEmpty(childList)){
			bomTreePage.setChildren(childList);
			for(MdmBomTreePage child : childList){
				child.setSumQty(bomTreePage.getSumQty().multiply(child.getPartQty()==null ? BigDecimal.ZERO : child.getPartQty()).setScale(2,BigDecimal.ROUND_HALF_UP));
				if("01".equals(levelType)){
					child.setKeyAndTitle();
					continue;
				}
				setMdmBomTree(child, levelType);
			}
		}
	}

	@Transactional
	@Override
	public void updateTree(MdmBomTreePage mdmBomTreePage) {
		// 保存主记录
		if(StringUtils.isBlank(mdmBomTreePage.getSuperMaterialId())){
			MdmBom mdmBom = new MdmBom();
			BeanUtils.copyProperties(mdmBomTreePage, mdmBom);
			mdmBomMapper.updateById(mdmBom);
		}else{
			MdmBomDetail mdmBomDetail = new MdmBomDetail();
			BeanUtils.copyProperties(mdmBomTreePage, mdmBomDetail);
			mdmBomDetailMapper.updateById(mdmBomDetail);
		}

		// 保存明细
		LambdaQueryWrapper<MdmBom> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(MdmBom::getMaterialId, mdmBomTreePage.getMaterialId());
		MdmBom bomMain = mdmBomMapper.selectOne(queryWrapper);
		if(bomMain == null){
			throw new RuntimeException("bom数据异常，未找到父级物料");
		}
		//1.先删除子表数据
		mdmBomDetailMapper.deleteByMainId(bomMain.getId());
		//2.子表数据重新插入
		List<MdmBomTreePage> children = mdmBomTreePage.getChildren();
		if(oConvertUtils.listIsNotEmpty(children)) {
			for(MdmBomTreePage child : children) {
				MdmBomDetail mdmBomDetail = new MdmBomDetail();
				BeanUtils.copyProperties(child, mdmBomDetail);
				//外键设置
				mdmBomDetail.setMainId(bomMain.getId());
				mdmBomDetail.setSuperMaterialId(bomMain.getMaterialId());
				mdmBomDetailMapper.insert(mdmBomDetail);
			}
		}
	}

	/**
	 * 多级BOM列表查询
	 *
	 * @param page
	 * @param mdmBomPage
	 * @return com.baomidou.mybatisplus.core.metadata.IPage<com.cinc.mdm.modules.bom.vo.MdmBomPage>
	 */
	@Override
	public IPage<MdmBomPage> findMultiLevelList(Page<MdmBomPage> page, MdmBomPage mdmBomPage){
		// 查询顶级bom列表
		if(StringUtils.isBlank(mdmBomPage.getMaterialCode())){
			mdmBomPage.setMaterialTypeCode("FERT");
		}
		IPage pageList = mdmBomMapper.selectPageList(page, mdmBomPage);
		List<MdmBomPage> topRecords = pageList.getRecords();
		if(oConvertUtils.listIsEmpty(topRecords)){
			return pageList;
		}

		List<MdmBomMutilLevelPage> allRecords = new ArrayList<>();
		// 构造多级列表
		if(oConvertUtils.listIsNotEmpty(topRecords)) {
			for(MdmBomPage bomPage : topRecords){
				List<MdmBomMutilLevelPage> bomMutilLevelList = mdmBomMapper.selectSingleLevelList(bomPage.getFactory(),bomPage.getMaterialId());
				bomMutilLevelList.forEach(multiLevelPage -> multiLevelPage.setSumQty(multiLevelPage.getPartQty()));
				allRecords.addAll(bomMutilLevelList);
				setMultiLevelList(bomMutilLevelList, allRecords);
			}
		}

		pageList.setRecords(allRecords);
		return pageList;
	}

	private void setMultiLevelList(List<MdmBomMutilLevelPage> bomMutilLevelList, List<MdmBomMutilLevelPage> allRecords){
		if(oConvertUtils.listIsNotEmpty(bomMutilLevelList)){
			for(MdmBomMutilLevelPage bomMutilLevelPage : bomMutilLevelList){
				List<MdmBomMutilLevelPage> childList = mdmBomMapper.selectSingleLevelList(bomMutilLevelPage.getFactory(),bomMutilLevelPage.getMaterialId());
				if(oConvertUtils.listIsEmpty(childList)){
					continue;
				}
				childList.forEach(child -> child.setSumQty(bomMutilLevelPage.getSumQty().multiply(child.getPartQty()==null?BigDecimal.ZERO:child.getPartQty()).setScale(2,BigDecimal.ROUND_HALF_UP)));
				allRecords.addAll(childList);
				setMultiLevelList(childList, allRecords);
			}
		}
	}
}
